package com.vca.service.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.vca.common.constants.Constants;
import com.vca.common.constants.SFConstants;
import com.vca.common.exception.VcaException;
import com.vca.common.model.sf.MsgData;
import com.vca.common.model.sf.MsgDataExpress;
import com.vca.common.model.sf.MsgDataIntercept;
import com.vca.common.model.sf.MsgDataUpdate;
import com.vca.common.response.sf.ExpressResponse;
import com.vca.common.response.sf.ResponseCancel;
import com.vca.common.response.sf.SFReturnData;
import com.vca.common.utils.DateUtil;
import com.vca.common.utils.HttpClientUtils;
import com.vca.common.utils.RestTemplateUtil;
import com.vca.service.service.SystemConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import sun.misc.BASE64Encoder;

import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 顺丰快递 Api 接口对接， 官网文档-零担下单： https://freight.sf-express.com/api/api.html#id=30
 * <p>
 * 请求头必须添加： "Content-type","application/x-www-form-urlencoded;charset=UTF-8”
 * </P>
 *
 * @author wangsong
 * @version 1.0.0
 * @mail 1720696548@qq.com
 * @date 2020/9/9 0009 9:38
 */

@Component
@Slf4j
public class SFUtil {

    @Autowired
    private RestTemplateUtil restTemplateUtil;

    @Autowired
    private SystemConfigService systemConfigService;


    /**
     * 顺丰寄件下单
     */
    public ResponseCancel fopReceLtlCreateOrder(MsgData md, Boolean disable) {
        //顺丰接口地址
        String url = systemConfigService.getValueByKey(Constants.SF_URL);
        String msgDatas = JSON.toJSONString(md);
        SFReturnData sfReturnData = http("EXP_RECE_CREATE_ORDER", msgDatas, url, disable);
        if (!"A1000".equals(sfReturnData.getApiResultCode())) {
            //失败
            log.info(sfReturnData.toString());
            throw new VcaException(sfReturnData.getApiErrorMsg());
        }
        String apiResultData = sfReturnData.getApiResultData();
        ResponseCancel responseCreate = JSON.parseObject(apiResultData, ResponseCancel.class);
        return responseCreate;
    }


    /**
     * 顺丰取消订单
     */
    public ResponseCancel fopReceLtlCancelOrder(MsgDataUpdate msgDataUpdate, Boolean disable) {
        //顺丰接口地址
        String url = systemConfigService.getValueByKey(Constants.SF_URL);
        String md = JSON.toJSONString(msgDataUpdate);
        SFReturnData sfReturnData = http("EXP_RECE_UPDATE_ORDER", md, url, disable);
        if (!"A1000".equals(sfReturnData.getApiResultCode())) {
            //失败
            log.info(sfReturnData.toString());
            throw new VcaException(sfReturnData.getApiErrorMsg());
        }
        String apiResultData = sfReturnData.getApiResultData();
        ResponseCancel responseCreate = JSON.parseObject(apiResultData, ResponseCancel.class);
        return responseCreate;
    }


    /**
     * 顺丰拦截取消订单
     */
    public ResponseCancel fopInterceptOrder(MsgDataIntercept msgDataIntercept, Boolean disable) {
        //顺丰接口地址
        String url = systemConfigService.getValueByKey(Constants.SF_URL);
        String md = JSON.toJSONString(msgDataIntercept);
        SFReturnData sfReturnData = http("EXP_RECE_WANTED_INTERCEPT", md, url, disable);
        if (!"A1000".equals(sfReturnData.getApiResultCode())) {
            //失败
            log.info(sfReturnData.toString());
            throw new VcaException(sfReturnData.getApiErrorMsg());
        }
        String apiResultData = sfReturnData.getApiResultData();
        ResponseCancel responseCreate = JSON.parseObject(apiResultData, ResponseCancel.class);
        return responseCreate;
    }

    /**
     * 下单结果查询
     */
    public ResponseCancel fopReceLtlGetOrderResult(String orderId, Boolean disable) {
        //顺丰接口地址
        String url = systemConfigService.getValueByKey(Constants.SF_URL);
        Map<String, String> param = new HashMap<>();
        param.put("orderId", orderId);
        param.put("searchType", "1");
        param.put("language", "zh-cn");
        String msgDatas = JSON.toJSONString(param);
        SFReturnData sfReturnData = http("EXP_RECE_SEARCH_ORDER_RESP", msgDatas, url, disable);

        if (!"A1000".equals(sfReturnData.getApiResultCode())) {
            //失败
            log.info(sfReturnData.toString());
            throw new VcaException(sfReturnData.getApiErrorMsg());
        }
        String apiResultData = sfReturnData.getApiResultData();
        ResponseCancel responseCreate = JSON.parseObject(apiResultData, ResponseCancel.class);
        return responseCreate;
    }

    /**
     * 订单路由查询
     */
    public ResponseCancel fopReceLtlGetOrderRouting(String masterWaybillNo, Boolean disable) {
        //顺丰接口地址
        String url = systemConfigService.getValueByKey(Constants.SF_URL);
        //手机号
        String phone = systemConfigService.getValueByKey(Constants.CONFIG_EXPORT_TO_TEL);

        Map<String, String> param = new HashMap<>();
        param.put("trackingType", "1");
        param.put("trackingNumber", masterWaybillNo);
        param.put("checkPhoneNo",phone.substring(phone.length()-4,phone.length()));
        String msgDatas = JSON.toJSONString(param);
        log.info("路由查询请求参数"+msgDatas);
        SFReturnData sfReturnData = http("EXP_RECE_SEARCH_ROUTES", msgDatas, url, disable);

        if (!"A1000".equals(sfReturnData.getApiResultCode())) {
            //失败
            log.info(sfReturnData.toString());
            throw new VcaException(sfReturnData.getApiErrorMsg());
        }
        String apiResultData = sfReturnData.getApiResultData();
        ResponseCancel responseCreate = JSON.parseObject(apiResultData, ResponseCancel.class);
        return responseCreate;
    }

    /**
     * 顺丰电子面单
     *
     * @param msgDataExpress
     * @return
     */
    public ExpressResponse getExpress(MsgDataExpress msgDataExpress, Boolean disable) {
        //顺丰接口地址
        String url = systemConfigService.getValueByKey(Constants.SF_URL);
        String md = JSON.toJSONString(msgDataExpress);
        SFReturnData sfReturnData = http("COM_RECE_CLOUD_PRINT_WAYBILLS", md, url, disable);
        if (!"A1000".equals(sfReturnData.getApiResultCode())) {
            //失败
            log.info(sfReturnData.toString());
            throw new VcaException(sfReturnData.getApiErrorMsg());
        }
        String apiResultData = sfReturnData.getApiResultData();
        ExpressResponse responseCreate = JSON.parseObject(apiResultData, ExpressResponse.class);
        return responseCreate;
    }


    private SFReturnData http(String serviceCode, String md, String url, Boolean disable) {
        String clientCode = systemConfigService.getValueByKey(Constants.CLIENT_CODE);
        String timestamp = System.currentTimeMillis() + "";
        String s = "";
        System.out.println("disable = " + disable);
        if (disable) {
            // TODO: 2023/1/12 UAT和PROD环境调用
            s = sendHttpProxy(serviceCode, md, url, clientCode, timestamp);
        } else {
            // TODO: 2023/1/12 开发环境调用
            s = sendHttp(serviceCode, md, url, clientCode, timestamp);
        }
        log.info("-----顺丰接口返回数据为：" + s);
        if (StringUtils.isEmpty(s)) {
            throw new VcaException("顺丰接口请求失败 无返回数据");
        }
        JSONObject sfJson = JSONObject.parseObject(s);
        Map<String, Object> innerMap = sfJson.getInnerMap();
        SFReturnData sfReturnData = new SFReturnData();
        //如果apiResultData为空说明第三方请求错误 并返回错误信息
        if (StringUtils.isEmpty(innerMap.get("apiResultData"))) {
            throw new VcaException(innerMap.get("apiErrorMsg").toString());
        }
        sfReturnData.setApiResponseID(innerMap.get("apiResponseID").toString());
        sfReturnData.setApiResultData(innerMap.get("apiResultData").toString());
        sfReturnData.setApiErrorMsg(innerMap.get("apiErrorMsg").toString());
        sfReturnData.setApiResultCode(innerMap.get("apiResultCode").toString());
        return sfReturnData;
    }

    public String sendHttp(String serviceCode, String md, String url, String clientCode, String timestamp) {
        //校验码
        String prodCheckCode = systemConfigService.getValueByKey(Constants.PROD_CHECK_CODE);
        // 发送快递参数处理
        MultiValueMap<String, String> sendBody = new LinkedMultiValueMap<String, String>();
        sendBody.add("partnerID", clientCode);
        sendBody.add("requestID", UUID.randomUUID().toString());
        sendBody.add("serviceCode", serviceCode);
        sendBody.add("timestamp", timestamp);
        sendBody.add("msgDigest", genDigest(timestamp, md, prodCheckCode));
        sendBody.add("msgData", md);
        //发送请求
        String s = restTemplateUtil.postFormData(url, sendBody);
        return s;
    }

    public String sendHttpProxy(String serviceCode, String md, String url, String clientCode, String timestamp) {
        //校验码
        String prodCheckCode = systemConfigService.getValueByKey(Constants.PROD_CHECK_CODE);
        HashMap<String, String> sendBody = new HashMap<String, String>();
        sendBody.put("partnerID", clientCode);
        sendBody.put("requestID", UUID.randomUUID().toString());
        sendBody.put("serviceCode", serviceCode);
        sendBody.put("timestamp", timestamp);
        sendBody.put("msgDigest", genDigest(timestamp, md, prodCheckCode));
        sendBody.put("msgData", md);
        String s = HttpClientUtils.doPostRequest(url, sendBody);
        return s;
    }

    public static void m() throws IOException {
        for (int i = 0; i >= 0; i++) {
            HashMap<String, String> sendBody = new HashMap<String, String>();
            String md = "{\"cargoDetails\":[{\"name\":\"2.6出版物测试 咯咯 \"}],\"contactInfoList\":[{\"address\":\"河南省 宁陵县宁陵县张弓镇大徐庄村\",\"contact\":\"李青岭\",\"contactType\":2,\"country\":\"CN\",\"mobile\":\"17537059027\",\"tel\":\"17537059027\"},{\"address\":\"上海市黄浦区淮海中路796号\\u2028历峰双子别墅\",\"contact\":\"L'ECOLE\",\"contactType\":1,\"country\":\"CN\",\"mobile\":\"17630038888\",\"tel\":\"17630038888\"}],\"expressTypeId\":1,\"isReturnRoutelabel\":1,\"language\":\"zh-CN\",\"monthlyCard\":\"7551234567\",\"orderId\":\"order81144167585083473734596\",\"parcelQty\":1}";
            String timestamp = System.currentTimeMillis() + "";
            sendBody.put("partnerID", "LYJMQz1J6i");
            sendBody.put("requestID", UUID.randomUUID().toString());
            sendBody.put("serviceCode", "EXP_RECE_CREATE_ORDER");
            sendBody.put("timestamp", timestamp);
            //将业务报文+时间戳+校验码组合成需加密的字符串(注意顺序)
            String toVerifyText = md + timestamp + "G1XfBiMTFpGn5Gyqkr6wLqRpbnXdCK2o";
            //因业务报文中可能包含加号、空格等特殊字符，需要urlEnCode处理
            FileWriter fileWriter = null;
            long l = 0;
            try {
                toVerifyText = URLEncoder.encode(toVerifyText, "UTF-8");
                //进行Md5加密
                MessageDigest md5 = MessageDigest.getInstance("MD5");
                md5.update(toVerifyText.getBytes("UTF-8"));
                byte[] md1 = md5.digest();
                //通过BASE64生成数字签名
                String msgDigest = new String(new BASE64Encoder().encode(md1));
                sendBody.put("msgDigest", msgDigest);
                sendBody.put("msgData", md);
                long start = System.currentTimeMillis();
                String s = HttpClientUtils.doPostRequest("https://sfapi-sbox.sf-express.com/std/service", sendBody);
                long end = System.currentTimeMillis();
                l = end - start;
                // TODO: 2023/2/9 写入文件
                fileWriter = new FileWriter("sf_log.txt", true);
                fileWriter.write("{\n");
                fileWriter.write("\t\t-------Start-------" + DateUtil.nowDateTime(Constants.DATE_FORMAT) + "--------------\n");
                fileWriter.write("\t\ttime = " + l + "\n");
                fileWriter.write("\t\tresult = " + s + "\n");
                if (l > 60000) {
//                    throw new VcaException("====================================读取超时================================");
                    fileWriter.write("\t\t====================================读取超时================================\n");
                }
            } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) {
                fileWriter.write("\t\ttime = " + l + "\n");
                fileWriter.write("\t\texception = \n" + e + "\n");
                e.printStackTrace();
            } catch (IOException e) {
                fileWriter.write("\t\ttime = " + l + "\n");
                fileWriter.write("\t\texception = \n" + e + "\n");
                throw new RuntimeException(e);
            } finally {
                try {
                    fileWriter.write("}\n\n");
                    fileWriter.flush();
                    fileWriter.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     * 业务数据加密
     *
     * @param timestamp
     * @param msgData
     * @param md5key
     * @return
     * @throws Exception
     */
    private String genDigest(String timestamp, String msgData, String md5key) {
        //将业务报文+时间戳+校验码组合成需加密的字符串(注意顺序)
        String toVerifyText = msgData + timestamp + md5key;
        //因业务报文中可能包含加号、空格等特殊字符，需要urlEnCode处理
        try {
            toVerifyText = URLEncoder.encode(toVerifyText, "UTF-8");
            //进行Md5加密
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(toVerifyText.getBytes("UTF-8"));
            byte[] md = md5.digest();
            //通过BASE64生成数字签名
            String msgDigest = new String(new BASE64Encoder().encode(md));
            return msgDigest;
        } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }


}

